// POJ 1274
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;

template <typename T, int MaxElement>
class RingQueue
{
public:
	void init()
	{
		fp = 0;
		bp = 0;
	}

	const T &front() const
	{
		return q[fp];
	}
	
	void pop()
	{
		if (++fp == MaxElement)
			fp = 0;
	}

	void push(const T &val)
	{
		q[bp] = val;
		if (++bp == MaxElement)
			bp = 0;
	}

	bool empty() const
	{
		return fp == bp;
	}

private:
	T q[MaxElement + 1];
	// front and the next of the back
	int fp, bp;
};

// 0-based
template <int NodeCount>
class MaxFlow
{
	enum
	{
		MaxInt = 0x7FFFFFFF
	};
public:
	MaxFlow()
	{
	}

	void init(int node)
	{
		nodeCnt = node;
		for (int i = 0; i < node; ++i)
			for (int j = 0; j < node; ++j)
				adj[i][j] = 0;
	}

	void addEdge(int a, int b, int weight)
	{
		adj[a][b] = weight;
	}

	int getMaxFlow(int src, int sink)
	{
		memset(inf, 0, sizeof(inf));
		while (1)
		{
			q.init();
			memset(path, 0xFF, sizeof(path));
			q.push(src);
			path[src] = src;
			pathFlow[src] = MaxInt;

			while (!q.empty())
			{
				int nd = q.front();
				if (nd == sink)
					break;
				q.pop();
				for (int i = 0; i < nodeCnt; ++i)
				{
					if (adj[nd][i] > 0 && path[i] == -1)
					{
						q.push(i);
						path[i] = nd;
						pathFlow[i] = min(pathFlow[nd], adj[nd][i]);
					}
				}
			}
			if (q.empty())
				break;

			int f = pathFlow[sink];
			inf[path[sink]] += f;
			int v = sink;
			while (v != path[v])
			{
				int prev = path[v];
				adj[prev][v] -= f;
				adj[v][prev] += f;
				v = prev;
			}
		}
		return accumulate(inf, inf + nodeCnt, 0);
	}

private:
	int adj[NodeCount][NodeCount];
	int nodeCnt;

	// tmp
	RingQueue<int, NodeCount> q;
	int path[NodeCount];
	int pathFlow[NodeCount];
	int inf[NodeCount];
};

int n, m;

MaxFlow<409> mf;

int main()
{
	while (scanf("%d%d", &n, &m) != EOF)
	{
		mf.init(n + m + 2);
		for (int i = 0; i < n; ++i)
			mf.addEdge(0, i + 1, 1);
		for (int i = 0; i < m; ++i)
			mf.addEdge(n + 1 + i, n + m + 1, 1);
		for (int i = 0; i < n; ++i)
		{
			int cnt;
			scanf("%d", &cnt);
			while (cnt--)
			{
				int v;
				scanf("%d", &v);
				mf.addEdge(i + 1, n + v, 1);
			}
		}
		printf("%d\n", mf.getMaxFlow(0, n + m + 1));
	}
	system("pause");
	return 0;
}

